package com.zhengqing.demo.util;

import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
import java.util.regex.Matcher;

import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.springframework.util.CollectionUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.zhengqing.demo.constant.AppConstant;
import com.zhengqing.demo.diff.html.HtmlDiff;
import com.zhengqing.demo.enums.DiffTypeEnum;
import com.zhengqing.demo.model.bo.DiffBO;
import com.zhengqing.demo.model.bo.DiffConditionBO;
import com.zhengqing.demo.model.bo.DiffDataBO;
import com.zhengqing.demo.model.bo.DiffShowBO;
import com.zhengqing.demo.model.bo.DiffTextInfoHandleBO;
import com.zhengqing.demo.model.bo.DiffTextStatisticsInfoBO;
import com.zhengqing.demo.model.bo.DiffTextStatisticsInfoBO.DiffTextInfoItem;

import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * html对比数据处理$
 * </p>
 *
 * @author : zhengqing
 * @description :
 * @date : 2020/12/4$ 14:25$
 */
@Slf4j
public class MyDiffHtmlHandleUtil {

    /**
     * 处理文本差异信息（判断是否显示背景样式标识）
     *
     * @param params:
     *            参数信息
     * @return: 差异文本信息
     * @author : zhengqing
     * @date : 2020/10/22 13:35
     */
    public DiffBO diff(DiffTextInfoHandleBO params) {
        // 1、判断支持哪些对比数据条件：插入、删除、修改、对调、移动
        DiffConditionBO diffCondition = this.handleCondition(params);

        // 新旧文本数据
        String htmlOld = params.getHtmlOld();
        String htmlNew = params.getHtmlNew();
        if (StringUtils.isBlank(htmlOld)) {
            htmlOld = "";
        }
        if (StringUtils.isBlank(htmlNew)) {
            htmlNew = "";
        }

        // 2、对比数据列表
        List<DiffDataBO> diffDataList = this.handleDiffDataList(htmlOld, htmlNew);

        // 3、判断是否为“增加、删除、修改、对调”显示样式
        List<DiffShowBO> diffShowList = this.handleDiffTypeAndIfShow(diffDataList, diffCondition);

        // 4、移出不要的元素数据
        diffShowList.removeIf(DiffShowBO::getIfRemoveCurrentElement);

        // 5、移动识别处理（字数大于等于3时处理移动文本）
        Boolean hasMove = diffCondition.getHasMove();
        if (hasMove) {
            this.handleDiffForMove(diffShowList);
        }

        // 6、统计差异文本信息
        DiffTextStatisticsInfoBO diffTextStatisticsInfo = this.handleDiffTextStatisticsData(diffShowList);

        // 7、对比文本差异结果 - 添加样式
        String diffContentHtml = this.addTagForText(diffShowList);

        // 8、封装返回结果
        DiffBO diffBO = new DiffBO();
        diffBO.setDiffContentHtml(diffContentHtml);
        diffBO.setDiffShowList(diffShowList);
        diffBO.setDiffTextStatisticsInfo(diffTextStatisticsInfo);
        return diffBO;
    }

    /**
     * 处理对比支持哪些数据类型（插入、删除、修改、对调、移动）
     *
     * @param params:
     *            参数
     * @return: 对比条件结果
     * @author : zhengqing
     * @date : 2020/11/5 14:30
     */
    private DiffConditionBO handleCondition(DiffTextInfoHandleBO params) {
        List<Integer> checkedDiffTypeList = params.getCheckedDiffTypeList();
        Boolean ifAllDiffType = params.getIfAllDiffType();
        if (ifAllDiffType == null) {
            ifAllDiffType = false;
        }

        // 是否支持插入、删除、修改、对调、移动
        boolean hasInsert = false;
        boolean hasDelete = false;
        boolean hasUpdate = false;
        boolean hasExChange = false;
        boolean hasMove = false;

        // 1、判断是否支持全部对比类型
        if (ifAllDiffType) {
            hasInsert = true;
            hasDelete = true;
            hasUpdate = true;
            hasExChange = true;
            hasMove = true;
        } else {
            // 2、判断支持哪些对比类型
            if (!CollectionUtils.isEmpty(checkedDiffTypeList)) {
                for (Integer diffType : checkedDiffTypeList) {
                    if (DiffTypeEnum.增加.getType().equals(diffType)) {
                        hasInsert = true;
                        continue;
                    }
                    if (DiffTypeEnum.删除.getType().equals(diffType)) {
                        hasDelete = true;
                        continue;
                    }
                    if (DiffTypeEnum.修改.getType().equals(diffType)) {
                        hasUpdate = true;
                        continue;
                    }
                    if (DiffTypeEnum.对调.getType().equals(diffType)) {
                        hasExChange = true;
                        continue;
                    }
                    if (DiffTypeEnum.移动.getType().equals(diffType)) {
                        hasMove = true;
                    }
                }
            }
        }

        // 3、封装处理结果
        DiffConditionBO result = new DiffConditionBO();
        result.setHasInsert(hasInsert);
        result.setHasDelete(hasDelete);
        result.setHasUpdate(hasUpdate);
        result.setHasExChange(hasExChange);
        result.setHasMove(hasMove);
        log.debug("《html对比》 对比条件类型 插入：【{}】 删除：【{}】 修改：【{}】 对调：【{}】 移动：【{}】", hasInsert, hasDelete, hasUpdate,
            hasExChange, hasMove);
        return result;
    }

    /**
     * 获取对比差异信息列表
     *
     * @param htmlOld:
     *            旧数据
     * @param htmlNew:
     *            新数据
     * @return: 对比差异信息列表
     * @author : zhengqing
     * @date : 2020/12/4 17:16
     */
    private List<DiffDataBO> handleDiffDataList(String htmlOld, String htmlNew) {
        HtmlDiff diff = new HtmlDiff(htmlOld, htmlNew);
        String diffHtml = diff.Build();
        List<DiffDataBO> diffDataBOList = Lists.newArrayList();
        Matcher matcherDiff = AppConstant.DIFF_PATTERN_CONTENT.matcher(diffHtml);
        // 未匹配下标
        int unMatchStartIndex = 0;
        while (matcherDiff.find()) {
            int startIndex = matcherDiff.start();
            int endIndex = matcherDiff.end();

            // 处理未匹配数据
            if (unMatchStartIndex != startIndex) {
                String unMatchDataStr = diffHtml.substring(unMatchStartIndex, startIndex);
                diffDataBOList.add(DiffDataBO.builder().typeEnum(DiffTypeEnum.不变).text(unMatchDataStr).build());
            }
            unMatchStartIndex = endIndex;

            // 处理匹配数据
            String diffContent = matcherDiff.group(0);
            String diffPlainText = matcherDiff.group(2);
            if (diffContent.startsWith("<ins")) {
                diffDataBOList.add(DiffDataBO.builder().typeEnum(DiffTypeEnum.增加).text(diffPlainText).build());
            }
            if (diffContent.startsWith("<del")) {
                diffDataBOList.add(DiffDataBO.builder().typeEnum(DiffTypeEnum.删除).text(diffPlainText).build());
            }
        }

        // 处理最后不变的未匹配数据
        int diffHtmlLength = diffHtml.length();
        if (unMatchStartIndex != diffHtmlLength) {
            String unMatchStr = diffHtml.substring(unMatchStartIndex);
            diffDataBOList.add(DiffDataBO.builder().typeEnum(DiffTypeEnum.不变).text(unMatchStr).build());
        }
        return diffDataBOList;
    }

    /**
     * 封装不同对比类型数据,判断是否为增加、删除、修改、对调、移动（字数大于等于3时处理移动文本）时显示样式
     *
     * @param diffList:
     *            对比差异数据
     * @param conditionInfo:
     *            对比条件
     * @return: 封装过后的对比差异数据
     * @author : zhengqing
     * @date : 2020/11/5 14:35
     */
    private List<DiffShowBO> handleDiffTypeAndIfShow(List<DiffDataBO> diffList, DiffConditionBO conditionInfo) {
        boolean hasInsert = conditionInfo.getHasInsert();
        boolean hasDelete = conditionInfo.getHasDelete();
        boolean hasUpdate = conditionInfo.getHasUpdate();
        boolean hasExChange = conditionInfo.getHasExChange();

        // 保存是否显示背景标识的最终对比数据
        List<DiffShowBO> diffShowList = Lists.newArrayList();

        // 1、遍历封装对比数据
        for (int i = 0; i < diffList.size(); i++) {
            // 当前文本信息
            DiffDataBO diffItemNow = diffList.get(i);
            String diffTextNow = diffItemNow.getText();
            DiffTypeEnum diffTypeEnumNow = diffItemNow.getTypeEnum();

            DiffShowBO diffShowNow = new DiffShowBO();
            diffShowNow.setDiff(diffItemNow);
            diffShowNow.setDiffText(diffTextNow);
            diffShowNow.setDiffTypeEnum(diffTypeEnumNow);
            diffShowNow.setIfShow(false);
            diffShowNow.setIfRemoveCurrentElement(false);

            // 当前文本数据类型
            boolean isInsert = false;
            boolean isDelete = false;
            boolean isEqual = false;
            switch (diffTypeEnumNow) {
                case 增加:
                    isInsert = true;
                    break;
                case 删除:
                    isDelete = true;
                    break;
                case 不变:
                    isEqual = true;
                    break;
                default:
                    break;
            }

            // 当前数据是否显示
            boolean ifShowInsert = hasInsert && isInsert;
            boolean ifShowDelete = hasDelete && isDelete;
            boolean ifShowCurrent = isEqual || ifShowInsert || ifShowDelete;

            // 2、第一个数据：判断“不变/新增/删除”是否显示
            if (i == 0) {
                diffShowNow.setIfShow(ifShowCurrent);
            }

            // 3、>1即之后的数据
            if (i > 0) {
                // 上一个文本数据
                DiffDataBO diffItemBefore = diffList.get(i - 1);
                DiffTypeEnum beforeTypeEnum = diffItemBefore.getTypeEnum();
                // 上一个装载的数据
                DiffShowBO diffShowDataBefore = diffShowList.get(i - 1);

                // 3.1、处理`修改`数据
                // 上一个删除 + 现在新增 = 修改
                if (hasUpdate) {
                    boolean isUpdate = beforeTypeEnum.equals(DiffTypeEnum.删除) && isInsert;
                    // 3.1.1、标识修改
                    if (isUpdate) {
                        this.handleDiffForUpdate(diffShowDataBefore, diffShowNow);
                    } else {
                        // 标识删除/新增/不变
                        diffShowNow.setIfShow(ifShowCurrent);
                    }
                } else {
                    // 3.1.2、标识删除/新增/不变
                    diffShowNow.setIfShow(ifShowCurrent);
                }

                // 3.2、处理`对调`数据 ( 新增+不变+删除 组合数据 ， 即 新增和删除数据一致为对调数据 ) ex: "这是测试数据" -> "试数据这是测"
                if (hasExChange && i > 1) {
                    DiffShowBO diffShowDataExChangeAfter = diffShowList.get(i - 2);
                    this.handleDiffForExChange(diffItemBefore, diffShowDataBefore, diffItemNow, diffShowNow,
                        diffShowDataExChangeAfter);
                }
            }
            diffShowNow.setIndex(i);
            diffShowList.add(diffShowNow);
        }
        return diffShowList;
    }

    /**
     * 处理对比-修改类型数据
     *
     * @param diffShowDataBefore:
     *            上一个数据
     * @param diffShowNow:
     *            当前数据
     * @return void
     * @author zhengqingya
     * @date 2021/3/11 17:13
     */
    private void handleDiffForUpdate(DiffShowBO diffShowDataBefore, DiffShowBO diffShowNow) {
        // ☆☆☆ 标识修改 ☆☆☆
        diffShowNow.setDiffTypeEnum(DiffTypeEnum.修改);
        // ① 设置本次显示样式
        diffShowNow.setIfShow(true);
        // ② 设置上次文本
        diffShowNow.setDiffTextBefore(diffShowDataBefore.getDiffText());
        // ③ 【设置上一次删除操作不显示样式 && 不显示删除文本】（即移除上一次删除的元素内容） && 【将删除文本保存作为`data-title`虚浮提示】
        diffShowDataBefore.setIfShow(false);
        diffShowDataBefore.setIfRemoveCurrentElement(true);
        diffShowDataBefore.setDiffTypeEnum(DiffTypeEnum.修改);
    }

    /**
     * 处理对比-对调类型数据
     *
     * @param diffItemBefore:
     *            原始上一个数据
     * @param diffShowDataBefore:
     *            装载中的上一个数据
     * @param diffItemNow:
     *            原始当前数据
     * @param diffShowNow:
     *            装载中的当前数据
     * @param diffShowDataExChangeAfter:
     *            装载中的对调后的数据
     * @return void
     * @author zhengqingya
     * @date 2021/3/11 17:23
     */
    private void handleDiffForExChange(DiffDataBO diffItemBefore, DiffShowBO diffShowDataBefore, DiffDataBO diffItemNow,
        DiffShowBO diffShowNow, DiffShowBO diffShowDataExChangeAfter) {
        // 对调后的数据 -> 新增数据
        DiffTypeEnum exChangeAfterDiffTypeEnum = diffShowDataExChangeAfter.getDiffTypeEnum();
        String exChangeAfterDiffText = diffShowDataExChangeAfter.getDiffText();
        // 新增+不变+删除 = 对调
        boolean isExChange =
            exChangeAfterDiffTypeEnum.equals(DiffTypeEnum.增加) && diffItemBefore.getTypeEnum().equals(DiffTypeEnum.不变)
                && diffItemNow.getTypeEnum().equals(DiffTypeEnum.删除);
        if (isExChange && diffShowNow.getDiffText().equals(exChangeAfterDiffText)) {
            // 【将新增数据和不变数据设置为一组对调数据】 && 【设置当前删除操作不显示样式 && 不显示删除文本】（即移除本次删除的元素内容）
            diffShowDataExChangeAfter.setDiffTextBefore(diffShowDataBefore.getDiffText());
            diffShowDataExChangeAfter.setDiffTypeEnum(DiffTypeEnum.对调);
            diffShowDataExChangeAfter.setIfRemoveCurrentElement(false);

            diffShowDataBefore.setIfShow(true);
            diffShowDataBefore.setDiffTextBefore(exChangeAfterDiffText);
            diffShowDataBefore.setDiffTypeEnum(DiffTypeEnum.对调);
            diffShowDataBefore.setIfRemoveCurrentElement(false);

            diffShowNow.setIfRemoveCurrentElement(true);
        }
    }

    /**
     * 处理移动数据（字数大于等于3时处理移动文本） - 识别删除和新增相同的文本，然后判断 *** （删除在前 & 新增在后） || （新增在前 &
     * 删除在后），在删除处插入转移标签并标识转移前文本数据，在新增处插入转移标签并标识转移后的现在文本数据
     *
     * @param diffShowList:
     *            差异数据列表信息
     * @return: 处理过后识别到移动的数据
     * @author : zhengqing
     * @date : 2020/11/4 10:22
     */
    private List<DiffShowBO> handleDiffForMove(List<DiffShowBO> diffShowList) {
        List<DiffShowBO> moveDeleteDataList = Lists.newArrayList();
        List<DiffShowBO> moveInsertDataList = Lists.newArrayList();
        for (DiffShowBO showDataItem : diffShowList) {
            DiffTypeEnum diffTypeEnum = showDataItem.getDiffTypeEnum();
            String diffText = showDataItem.getDiffText();
            if (StringUtils.isBlank(diffText) || diffText.length() < 3) {
                continue;
            }
            if (diffTypeEnum.equals(DiffTypeEnum.删除)) {
                moveDeleteDataList.add(showDataItem);
            }
            if (diffTypeEnum.equals(DiffTypeEnum.增加)) {
                moveInsertDataList.add(showDataItem);
            }
        }

        if (CollectionUtils.isEmpty(moveDeleteDataList) || CollectionUtils.isEmpty(moveInsertDataList)) {
            return diffShowList;
        }

        // 用于判断该数据是否已经绑定过移动的数据标识
        Set<Integer> moveInsertIndexSet = Sets.newHashSet();

        boolean ifHasMoveData;
        DiffShowBO moveDeleteItem;
        DiffShowBO moveInsertItem;
        String diffTextDelete;
        String diffTextInsert;
        Integer moveDeleteItemIndex = null;
        Integer moveInsertItemIndex = null;
        Matcher matcherDelete = null;
        Matcher matcherInsert = null;

        for (int i = 0; i < moveDeleteDataList.size(); i++) {
            ifHasMoveData = false;
            moveDeleteItem = moveDeleteDataList.get(i);
            diffTextDelete = moveDeleteItem.getDiffText();

            for (int j = 0; j < moveInsertDataList.size(); j++) {
                moveInsertItem = moveInsertDataList.get(j);
                diffTextInsert = moveInsertItem.getDiffText();
                // （如果删除文本与新增文本相同） & （新增文本未出现过匹配的数据） -> 则 计入 移动数据
                // 先对`差异内容`进行处理，去掉开始和结尾的`\n\r`换行符再判断是否相等
                matcherDelete = AppConstant.TEXT_PATTERN_CENTER_CONTENT_LINE_FEED.matcher(diffTextDelete);
                while (matcherDelete.find()) {
                    diffTextDelete = matcherDelete.group();
                }
                matcherInsert = AppConstant.TEXT_PATTERN_CENTER_CONTENT_LINE_FEED.matcher(diffTextInsert);
                while (matcherInsert.find()) {
                    diffTextInsert = matcherInsert.group();
                }
                if (diffTextDelete.equals(diffTextInsert) && !moveInsertIndexSet.contains(j)) {
                    moveInsertIndexSet.add(j);
                    ifHasMoveData = true;
                    moveDeleteItemIndex = moveDeleteItem.getIndex();
                    moveInsertItemIndex = moveInsertItem.getIndex();
                    break;
                }
            }

            if (ifHasMoveData) {
                for (DiffShowBO showDataItem : diffShowList) {
                    Integer currentIndex = showDataItem.getIndex();
                    // 将删除&新增的数据设置会移动数据类型
                    boolean isMoveDeleteIndex = currentIndex.equals(moveDeleteItemIndex);
                    boolean isMoveInsertIndex = currentIndex.equals(moveInsertItemIndex);
                    if (isMoveDeleteIndex || isMoveInsertIndex) {
                        showDataItem.setDiffTypeEnum(DiffTypeEnum.移动);
                        showDataItem.setIfShow(true);
                        // 在识别到的移动插入数据类型处将移动标识修改为删除的标识，组合成一对数据，返回给前端处理
                        if (isMoveInsertIndex) {
                            showDataItem.setIndex(moveDeleteItemIndex);
                        }
                    }
                }
            }
        }
        return diffShowList;
    }

    /**
     * 统计差异文本信息
     *
     * @param diffShowList:
     *            差异数据列表信息
     * @return: 差异文本统计信息
     * @author : zhengqing
     * @date : 2020/11/9 15:08
     */
    private DiffTextStatisticsInfoBO handleDiffTextStatisticsData(List<DiffShowBO> diffShowList) {
        DiffTextStatisticsInfoBO diffTextInfo = new DiffTextStatisticsInfoBO();

        // 定义统计数据值
        int addNum = 0;
        int deleteNum = 0;
        int updateNum = 0;
        int exchangeNum = 0;
        int moveNum = 0;
        boolean ifOperated = false;
        List<DiffTextInfoItem> textInfoAddList = Lists.newArrayList();
        List<DiffTextInfoItem> textInfoDeleteList = Lists.newArrayList();
        List<DiffTextInfoItem> textInfoUpdateList = Lists.newArrayList();
        List<DiffTextInfoItem> textInfoExchangeList = Lists.newArrayList();
        List<DiffTextInfoItem> textInfoMoveList = Lists.newArrayList();

        if (!CollectionUtils.isEmpty(diffShowList)) {
            for (DiffShowBO diffDataItem : diffShowList) {
                DiffTypeEnum diffTypeEnum = diffDataItem.getDiffTypeEnum();
                boolean ifShow = diffDataItem.getIfShow();

                // 只要不是不变的内容都算 `修改/删除/新增` 操作过的内容
                if (!diffTypeEnum.equals(DiffTypeEnum.不变) && ifShow) {
                    ifOperated = true;
                    DiffTextInfoItem diffTextInfoItem = new DiffTextInfoItem();
                    String diffText = diffDataItem.getDiffText();
                    if (StringUtils.isBlank(diffText)) {
                        // continue;
                    }
                    diffTextInfoItem.setText(diffText);
                    diffTextInfoItem.setType(diffTypeEnum.getType());
                    diffTextInfoItem.setTypeName(diffTypeEnum.getDesc());

                    // 这里开始统计不同数据类型的文本数量
                    if (StringUtils.isNotBlank(diffText)) {
                        switch (diffTypeEnum) {
                            case 增加:
                                addNum++;
                                textInfoAddList.add(diffTextInfoItem);
                                break;
                            case 删除:
                                deleteNum++;
                                textInfoDeleteList.add(diffTextInfoItem);
                                break;
                            case 修改:
                                updateNum++;
                                diffTextInfoItem.setTextBefore(diffDataItem.getDiffTextBefore());
                                textInfoUpdateList.add(diffTextInfoItem);
                                break;
                            case 对调:
                                exchangeNum++;
                                diffTextInfoItem.setTextBefore(diffDataItem.getDiffTextBefore());
                                textInfoExchangeList.add(diffTextInfoItem);
                                break;
                            case 移动:
                                moveNum++;
                                diffTextInfoItem.setTextBefore(diffDataItem.getDiffTextBefore());
                                textInfoMoveList.add(diffTextInfoItem);
                                break;
                            default:
                                break;
                        }
                    }
                }
            }
        }

        // 装载数据
        diffTextInfo.setAddNum(addNum);
        diffTextInfo.setDeleteNum(deleteNum);
        diffTextInfo.setUpdateNum(updateNum);
        diffTextInfo.setExchangeNum(exchangeNum == 0 ? 0 : exchangeNum / 2);
        diffTextInfo.setMoveNum(moveNum == 0 ? 0 : moveNum / 2);
        diffTextInfo.setTextInfoAddList(textInfoAddList);
        diffTextInfo.setTextInfoDeleteList(textInfoDeleteList);
        diffTextInfo.setTextInfoUpdateList(textInfoUpdateList);
        diffTextInfo.setTextInfoExchangeList(textInfoExchangeList);
        diffTextInfo.setTextInfoMoveList(textInfoMoveList);
        diffTextInfo.setIfOperated(ifOperated);
        return diffTextInfo;
    }

    /**
     * 正则表达式替换匹配内容并为其加标签
     *
     * @param diffShowList:
     *            对比数据
     * @return: 拿到对比后差异文本信息
     * @author : zhengqing
     * @date : 2020/10/30 13:59
     */
    private String addTagForText(List<DiffShowBO> diffShowList) {
        StringJoiner diffHtml = new StringJoiner("");
        for (DiffShowBO diffItem : diffShowList) {
            boolean ifShow = diffItem.getIfShow();
            Integer index = diffItem.getIndex();
            String diffText = diffItem.getDiffText();
            DiffTypeEnum diffTypeEnum = diffItem.getDiffTypeEnum();
            DiffDataBO diff = diffItem.getDiff();
            DiffTypeEnum oldTypeEnum = diff.getTypeEnum();
            String diffTextBefore = diffItem.getDiffTextBefore();
            // 反转义HTML处理
            diffTextBefore = this.escapeHtml(diffTextBefore);
            switch (diffTypeEnum) {
                case 增加:
                    diffText =
                        ifShow ? String.format(AppConstant.TEXT_DIFF_HTML_CODE_TEXT_INSERT, "%s", "%s", "%s", diffText)
                            : diffText;
                    break;
                case 删除:
                    diffText = ifShow
                        ? String.format(AppConstant.TEXT_DIFF_HTML_CODE_TEXT_DELETE, "%s", "%s", "%s", diffText) : "";
                    break;
                case 修改:
                    diffText = String.format(AppConstant.TEXT_DIFF_HTML_CODE_TEXT_UPDATE, "%s", "%s", diffTextBefore,
                        diffText);
                    break;
                case 对调:
                    if (DiffTypeEnum.增加 == oldTypeEnum) {
                        diffText = String.format(AppConstant.TEXT_DIFF_HTML_CODE_TEXT_EXCHANGE_BEFORE, "%s", "%s",
                            diffTextBefore, diffText);
                    }
                    if (DiffTypeEnum.不变 == oldTypeEnum) {
                        diffText = String.format(AppConstant.TEXT_DIFF_HTML_CODE_TEXT_EXCHANGE_AFTER, "%s", "%s",
                            diffTextBefore, diffText);
                    }
                    break;
                case 移动:
                    if (DiffTypeEnum.删除 == oldTypeEnum) {
                        diffText = String.format(AppConstant.TEXT_DIFF_HTML_CODE_TEXT_MOVE_BEFORE, index, "%s", "%s",
                            diffText);
                    }
                    if (DiffTypeEnum.增加 == oldTypeEnum) {
                        diffText =
                            String.format(AppConstant.TEXT_DIFF_HTML_CODE_TEXT_MOVE_AFTER, index, "%s", "%s", diffText);
                    }
                    break;
                default:
                    break;
            }
            diffHtml.add(diffText);
        }
        return this.addCssForText(diffHtml.toString());
    }

    /**
     * 正则表达式替换匹配内容并为其加标签 - 针对原生数据（新增/删除）
     *
     * @param diffList:
     *            对比数据
     * @return: 拿到对比后差异文本信息
     * @author : zhengqing
     * @date : 2021/1/19 15:40
     */
    public String addTagForBasicText(List<DiffDataBO> diffList) {
        StringJoiner diffHtml = new StringJoiner("");
        for (DiffDataBO diffItem : diffList) {
            String diffText = diffItem.getText();
            Integer diffVersion = diffItem.getVersion();
            DiffTypeEnum diffTypeEnum = diffItem.getTypeEnum();
            switch (diffTypeEnum) {
                case 增加:
                    diffText =
                        String.format(AppConstant.TEXT_DIFF_HTML_CODE_TEXT_INSERT, diffVersion, "%s", "%s", diffText);
                    break;
                case 删除:
                    diffText =
                        String.format(AppConstant.TEXT_DIFF_HTML_CODE_TEXT_DELETE, diffVersion, "%s", "%s", diffText);
                    break;
                default:
                    break;
            }
            diffHtml.add(diffText);
        }
        return this.addCssForText(diffHtml.toString());
    }

    /**
     * 添加css样式
     *
     * @param diffHtml:
     *            对比文本差异信息
     * @return: 处理数据
     * @author : zhengqing
     * @date : 2020/12/7 13:42
     */
    private String addCssForText(String diffHtml) {
        Document doc = Jsoup.parseBodyFragment(diffHtml);
        Element head = doc.head();
        head.append(AppConstant.DIFF_CSS);
        return doc.html();
    }

    /**
     * html转义处理
     *
     * @param html:
     *            富文本
     * @return: 处理过后的html
     * @author : zhengqing
     * @date : 2020/10/27 11:42
     */
    private String escapeHtml(String html) {
        if (StringUtils.isBlank(html)) {
            return html;
        }
        // html转义处理
        html = html.replaceAll("\"", "&quot;");
        html = html.replaceAll("<", "&lt;");
        html = html.replaceAll(">", "&gt;");
        return html;
    }

}
